package com.bestv.search.common.dao.hibernate;

import com.bestv.search.common.dao.AccessLogDao;
import com.bestv.search.common.model.AccessLog;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class AccessLogDaoHibernate extends GenericDaoHibernate<AccessLog, Long> implements AccessLogDao {

    @Override
    public AccessLog get(int type, Date accessLowerTime, String siteCode, int serverNo) {

        Object[] values = {type, accessLowerTime, siteCode, serverNo};
        List<AccessLog> logs = executeQuery(
                "from AccessLog where type = ? and accessLowerTime =? and siteCode = ? and serverNo = ?", values);

        return logs == null || logs.size() == 0 ? null : logs.get(0);
    }

    @Override
    public List<AccessLog> get(Date accessLowerTime, Date accessUpperTime) {
        Object[] values = {accessLowerTime, accessUpperTime};
        return executeQuery("from AccessLog where accessLowerTime between ? and ? order accessDate asc", values);
    }

    @Override
    public List<AccessLog> get(Date accessLowerTime, Date accessUpperTime, int[] types, int serverNo) {
        int length = 2;
        if (serverNo != 0) {
            length = 3;
        }
        StringBuilder hql = new StringBuilder();
        Object[] values = new Object[types.length + length];
        values[0] = accessLowerTime;
        Calendar c = Calendar.getInstance();
        c.setTime(accessUpperTime);
        c.set(Calendar.MILLISECOND, 0);
        values[1] = c.getTime();
        hql.append("from AccessLog where accessLowerTime >= ? and  accessLowerTime < ? ");
        if (serverNo != 0) {
            values[2] = serverNo;
            hql.append(" and serverNo = ? ");
        }

        hql.append("and type in (");
        for (int i = 0; i < types.length; i++) {
            values[i + length] = types[i];
            hql.append("?");
            if (i == types.length - 1)
                hql.append(") order by accessLowerTime, type asc");
            else
                hql.append(",");
        }

        return executeQuery(hql.toString(), values);
    }

    @Override
    public List<AccessLog> getByMonth(Date startMonth, Date endMonth, int[] types) {

        Session session = getSession();
        ScrollableResults rs = null;

        List<AccessLog> result = new ArrayList<AccessLog>();
        try {
            StringBuilder hql = new StringBuilder();

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
            String start = format.format(startMonth);
            String end = format.format(endMonth);

            String hqlheader = "Select type, description, DATE_FORMAT(accessLowerTime, '%Y-%m') as accessMonth, "
                    + "sum(accessLog.count) as count from AccessLog as accessLog where DATE_FORMAT(accessLowerTime, '%Y-%m')>='"
                    + start + "' and DATE_FORMAT(accessLowerTime, '%Y-%m')<='" + end + "' and type in (";

            hql.append(hqlheader);
            for (int i = 0; i < types.length; i++) {
                hql.append(types[i]);
                if (i == types.length - 1)
                    hql.append(") group by DATE_FORMAT(accessLowerTime, '%Y-%m'), type "
                            + "order by DATE_FORMAT(accessLowerTime, '%Y-%m'), type asc");
                else
                    hql.append(",");
            }

            rs = session.createQuery(hql.toString()).scroll();
            while (rs.next()) {
                AccessLog log = new AccessLog();
                log.setType(rs.getInteger(0));
                log.setDescription(rs.getString(1));

                // Gets accessMonth from the third column
                String accessMonth = rs.getString(2);
                Calendar c = Calendar.getInstance();
                c.set(Calendar.YEAR, Integer.parseInt(accessMonth.substring(0, 4)));
                c.set(Calendar.MONTH, Integer.parseInt(accessMonth.substring(5, 7)) - 1);
                // set day to first day
                c.set(Calendar.DAY_OF_MONTH, 1);
                log.setAccessLowerTime(c.getTime());

                log.setCount(rs.getLong(3).intValue());
                result.add(log);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (rs != null)
                rs.close();
            if (session != null)
                releaseSession(session);
        }

        return result;
    }

    @Override
    public List<AccessLog> getByDate(Date startDate, Date endDate, int[] types) {

        Session session = getSession();
        ScrollableResults rs = null;

        List<AccessLog> result = new ArrayList<AccessLog>();
        try {
            StringBuilder hql = new StringBuilder();

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            String start = format.format(startDate);
            String end = format.format(endDate);

            String hqlheader = "Select type, description, DATE_FORMAT(accessLowerTime, '%Y-%m-%d') as accessMonth, "
                    + "sum(accessLog.count) as count from AccessLog as accessLog where DATE_FORMAT(accessLowerTime, '%Y-%m-%d')>='"
                    + start + "' and DATE_FORMAT(accessLowerTime, '%Y-%m-%d')<='" + end + "' and type in (";

            hql.append(hqlheader);
            for (int i = 0; i < types.length; i++) {
                hql.append(types[i]);
                if (i == types.length - 1)
                    hql.append(") group by DATE_FORMAT(accessLowerTime, '%Y-%m-%d'), type "
                            + "order by DATE_FORMAT(accessLowerTime, '%Y-%m-%d'), type asc");
                else
                    hql.append(",");
            }

            rs = session.createQuery(hql.toString()).scroll();
            while (rs.next()) {
                AccessLog log = new AccessLog();
                log.setType(rs.getInteger(0));
                log.setDescription(rs.getString(1));

                // Gets accessMonth from the third column
                String accessMonth = rs.getString(2);
                Calendar c = Calendar.getInstance();
                c.set(Calendar.YEAR, Integer.parseInt(accessMonth.substring(0, 4)));
                c.set(Calendar.MONTH, Integer.parseInt(accessMonth.substring(5, 7)) - 1);
                c.set(Calendar.DAY_OF_MONTH, Integer.parseInt(accessMonth.substring(8, 10)));
                log.setAccessLowerTime(c.getTime());

                log.setCount(rs.getLong(3).intValue());
                result.add(log);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (rs != null)
                rs.close();
            if (session != null)
                releaseSession(session);
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    private List<AccessLog> executeQuery(String queryString, Object[] values) {
        return getHibernateTemplate().find(queryString, values);
    }
}